DartVM Timer
介绍
Dart 虚拟机中的定时器,代码位于 sdk/lib/async/timer.dart,这是一个抽象类。
有两种工作模式,单次触发和循环触发。
Timer 构造
位于 sdk/lib/async/timer.dart。
根据定时器的触发模式,有两种构造方式:
Timer 工厂构造方法:
- 创建的是单次触发的定时器。
- 这里面的具体 Timer 对象创建,是通过 Zone 来创建的,并且还对是否是 Root Zone 进行了区分。
对应代码:
factory Timer(Duration duration, void Function() callback) {
if (Zone.current == Zone.root) {
return Zone.current.createTimer(duration, callback);
}
return Zone.current
.createTimer(
duration,
Zone.current.bindCallbackGuarded(callback));
}
Timer.periodic 工厂构造方法:
- 创建的是重复触发的定时器。
- 跟单次的类似,也是通过 Zone 进行创建。
createTimer 底层调用链梳理
一、Timer 构造函数
从上面代码中摘出这一行:
Zone.current.createTimer(duration, callback);
来到 sdk/lib/async/zone.dart 的 Zone 抽象类的 createTimer 抽象方法:
Timer createTimer(Duration duration, void Function() callback);
这里以 Root Zone 为例,看 _RootZone 的 createTimer:
Timer createTimer(Duration duration, void f()) {
return Timer._createTimer(duration, f);
}
回到 timer.dart 的 _createTimer 方法:
external static Timer _createTimer(Duration duration, void Function() callback);
external static Timer _createPeriodicTimer(Duration duration, void callback(Timer timer));
这是一个 external 方法,实现位于 sdk/lib/_internal/vm/lib/timer_patch.dart 的 Timer 类:
@patch
class Timer {
@patch
static Timer _createTimer(Duration duration, void callback()) {
final factory = VMLibraryHooks.timerFactory;
if (factory == null) {
throw new UnsupportedError("Timer interface not supported.");
}
int milliseconds = duration.inMilliseconds;
if (milliseconds < 0) milliseconds = 0;
return factory(
milliseconds,
(_) { callback();},
false);
}
关键方法是这个 factory。factory 哪里注入的?在 /sdk/lib/_internal/vm/lib/timer_impl.dart,里面声明了一个全局入口方法 _setupHooks:
@pragma("vm:entry-point", "call")
_setupHooks() {
VMLibraryHooks.timerFactory = _Timer._factory;
}
可以看到,最终实现方法是 _Timer 的 _factory。这个方法实现在同一个文件中:
// The Timer factory registered with the dart:async library by the embedder.
static Timer _factory(
int milliSeconds, void callback(Timer timer), bool repeating) {
if (repeating) {
return new _Timer.periodic(milliSeconds, callback);
}
return new _Timer(milliSeconds, callback);
}
这里以单次触发的定时器为例。对照上面的 factory 传参来看。
- milliseconds:定时器延时
- callback:定时器触发回调,这个 callback 网上追溯,是开发者传入的 callback
- repeating:单次触发还是循环触发
接下来的操作进入 _Timer 类一节来看了。
还有一点需要注意,在 Dart 中,创建好定时器 Timer 后,并不会自动开始,需要调用 start 方法后,才会开始定时器操作。
_Timer 类
这个类位于 /sdk/lib/_internal/vm/lib/timer_impl.dart。Timer 是一个抽象类,_Timer 是其实现类。
二叉堆
Dart 程序中包含多个定时器,在 DartVM 需要进行统一维护,根据定时器的预订时间进行触发调度。为了记录这些定时器的时间,采用二叉堆数据结构进行维护。
对应的成员是:
static final _heap = new _TimerHeap();
_createTimer
在上面的代码中,通过 _Timer 的构造函数返回 Timer 对象,对应的实现是:
factory _Timer(int milliSeconds, void callback(Timer timer)) {
return _createTimer(callback, milliSeconds, false);
}
可以看到,实际实现在 _createTimer 方法:
static _Timer _createTimer(
void callback(Timer timer), int milliSeconds, bool repeating) {
// 如果定时器延时小于0,认为就是0
if (milliSeconds < 0) {
milliSeconds = 0;
}
// 获取当前时间戳
int now = VMLibraryHooks.timerMillisecondClock();
int wakeupTime = (milliSeconds == 0) ? now : (now + 1 + milliSeconds);
// 通过 _Timer._internal 创建实际 _Timer 实例
_Timer timer =
new _Timer._internal(callback, wakeupTime, milliSeconds, repeating);
// 有一个入队操作
timer._enqueue();
return timer;
}
先看 _Timer 实例的创建:
_Timer._internal(
this._callback, this._wakeupTime, this._milliSeconds, this._repeating)
: _id = _nextId();
可以看到,这个构造函数以保存构造参数为主,同时自动创建了一个 id。 接下来再看这个入队操作:
void _enqueue() {
if (_milliSeconds == 0) {
if (_firstZeroTimer == null) {
_lastZeroTimer = this;
_firstZeroTimer = this;
} else {
_lastZeroTimer._indexOrNext = this;
_lastZeroTimer = this;
}
// Every zero timer gets its own event.
_notifyZeroHandler();
} else {
_heap.add(this);
if (_heap.isFirst(this)) {
_notifyEventHandler();
}
}
}
其中:
- 如果定时器延时为 0,是将定时器加入到一个全局链表当中
- 如果定时器延时大于0,则添加到二叉堆当中
这里有两个通知函数:
- _notifyZeroHandler
- _notifyEventHandler
这里的通知机制,是接下来需要看的重点。
小细节
设置一个负数延时,相当于延时为 0。